from fastapi import FastAPI, File, UploadFile, Form, HTTPException, BackgroundTasks, Request
from fastapi.responses import JSONResponse, FileResponse, HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
import os
import shutil
import tempfile
from typing import Optional, List
from service import ZipMdMergeService
import uuid


@asynccontextmanager
async def lifespan(app: FastAPI):
    # 启动时执行
    print("🚀 ZIP MD 合并工具启动成功!")
    print("📝 访问 Web 界面（根据部署环境可能为 http://localhost:8000 或通过环境配置生产域名BASE_URL=https://dots-ocr-online-deal-project-backup.onrender.com）")
    print("📊 访问 /docs 查看API文档")
    yield
    # 关闭时执行（如果需要的话）
    print("📴 应用正在关闭...")


app = FastAPI(
    title="ZIP MD 合并工具",
    description="将ZIP文件中的Markdown文件合并并转换HTML表格为Markdown格式",
    version="1.0.0",
    lifespan=lifespan
)

# 添加 CORS 中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 生产环境中应指定前端域名，例如 ["https://your-frontend.com"]
    allow_credentials=True,
    allow_methods=["*"],  # 允许所有 HTTP 方法
    allow_headers=["*"],  # 允许所有头部
)

# 初始化服务
service = ZipMdMergeService()

# 创建必要的目录
os.makedirs("uploads", exist_ok=True)
os.makedirs("outputs", exist_ok=True)
os.makedirs("static", exist_ok=True)

# 挂载静态文件目录
app.mount("/static", StaticFiles(directory="static"), name="static")
app.mount("/outputs", StaticFiles(directory="outputs"), name="outputs")

# 默认基地址（本地开发用）
DEFAULT_BASE_URL = "http://localhost:8000"


@app.get("/", response_class=HTMLResponse)
async def root(request: Request):
    """主页面 - 提供简单的Web界面"""
    # 动态获取基地址
    base_url = os.getenv("BASE_URL", DEFAULT_BASE_URL)
    html_content = f"""
    <!DOCTYPE html>
    <html>
    <head>
        <title>ZIP MD 合并工具</title>
        <meta charset="utf-8">
        <style>
            body {{ font-family: Arial, sans-serif; margin: 40px; background-color: #f5f5f5; }}
            .container {{ max-width: 800px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }}
            h1 {{ color: #333; text-align: center; margin-bottom: 30px; }}
            .form-group {{ margin-bottom: 20px; }}
            label {{ display: block; margin-bottom: 8px; font-weight: bold; color: #555; }}
            input[type="file"] {{ width: 100%; padding: 12px; border: 2px solid #ddd; border-radius: 6px; }}
            input[type="number"] {{ width: 200px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }}
            button {{ background-color: #007bff; color: white; padding: 12px 30px; border: none; cursor: pointer; border-radius: 6px; font-size: 16px; }}
            button:hover {{ background-color: #0056b3; }}
            button:disabled {{ background-color: #ccc; cursor: not-allowed; }}
            .checkbox-group {{ margin: 15px 0; }}
            .checkbox-group label {{ display: inline; margin-left: 8px; font-weight: normal; }}
            .result {{ margin-top: 30px; padding: 20px; background-color: #f8f9fa; border-radius: 6px; border-left: 4px solid #007bff; }}
            .file-link {{ display: block; margin: 8px 0; padding: 10px; background: #e3f2fd; border-radius: 4px; color: #1976d2; text-decoration: none; }}
            .file-link:hover {{ background: #bbdefb; text-decoration: underline; }}
            .error {{ color: #dc3545; background-color: #f8d7da; padding: 15px; border-radius: 6px; margin: 10px 0; }}
            .success {{ color: #28a745; background-color: #d4edda; padding: 15px; border-radius: 6px; margin: 10px 0; }}
            .loading {{ text-align: center; margin: 20px 0; }}
            .progress {{ width: 100%; height: 6px; background-color: #e0e0e0; border-radius: 3px; overflow: hidden; margin: 10px 0; }}
            .progress-bar {{ height: 100%; background-color: #007bff; width: 0%; transition: width 0.3s ease; }}
        </style>
    </head>
    <body>
        <div class="container">
            <h1>📄 ZIP MD 合并工具</h1>
            <p style="text-align: center; color: #666; margin-bottom: 30px;">
                上传包含 Markdown 文件的 ZIP 压缩包，工具将自动合并并转换HTML表格为Markdown格式
            </p>
            
            <form id="uploadForm" enctype="multipart/form-data">
                <div class="form-group">
                    <label for="file">📁 选择 ZIP 文件:</label>
                    <input type="file" id="file" name="file" accept=".zip" required>
                </div>
                
                <div class="checkbox-group">
                    <input type="checkbox" id="transfer_html" name="transfer_html" checked>
                    <label for="transfer_html">🔄 转换HTML表格为Markdown格式</label>
                </div>
                
                <div class="form-group">
                    <label for="max_files_per_group">📊 每组最大文件数:</label>
                    <input type="number" id="max_files_per_group" name="max_files_per_group" value="10" min="1" max="100">
                    <small style="color: #666;">设置每个输出文件包含的最大页面数</small>
                </div>
                
                <button type="submit" id="submitBtn">🚀 开始处理</button>
            </form>
            
            <div id="loading" class="loading" style="display: none;">
                <p>⏳ 正在处理文件，请稍候...</p>
                <div class="progress">
                    <div class="progress-bar" id="progressBar"></div>
                </div>
            </div>
            
            <div id="result" class="result" style="display: none;"></div>
        </div>

        <script>
            document.getElementById('uploadForm').addEventListener('submit', async function(e) {{
                e.preventDefault();
                
                const formData = new FormData();
                const fileInput = document.getElementById('file');
                const transferHtml = document.getElementById('transfer_html').checked;
                const maxFiles = document.getElementById('max_files_per_group').value;
                
                if (!fileInput.files[0]) {{
                    alert('请选择一个ZIP文件');
                    return;
                }}
                
                formData.append('file', fileInput.files[0]);
                formData.append('transfer_html', transferHtml);
                formData.append('max_files_per_group', maxFiles);
                
                // 显示加载状态
                document.getElementById('loading').style.display = 'block';
                document.getElementById('result').style.display = 'none';
                document.getElementById('submitBtn').disabled = true;
                
                // 模拟进度条
                let progress = 0;
                const progressBar = document.getElementById('progressBar');
                const progressInterval = setInterval(() => {{
                    progress += Math.random() * 20;
                    if (progress > 90) progress = 90;
                    progressBar.style.width = progress + '%';
                }}, 500);
                
                try {{
                    const response = await fetch('{base_url}/zip_md_merge', {{
                        method: 'POST',
                        body: formData
                    }});
                    
                    clearInterval(progressInterval);
                    progressBar.style.width = '100%';
                    
                    const result = await response.json();
                    
                    document.getElementById('loading').style.display = 'none';
                    document.getElementById('submitBtn').disabled = false;
                    
                    if (response.ok) {{
                        let resultHtml = '<div class="success"><strong>✅ 处理成功！</strong></div>';
                        resultHtml += '<h3>📋 生成的ZIP文件:</h3>';
                        
                        // 显示ZIP文件的下载链接
                        const fileName = result.zip_file.split('/').pop();
                        resultHtml += `<a href="${{result.zip_file}}" class="file-link" target="_blank">📦 ${{fileName}}</a>`;
                        
                        resultHtml += `<p style="margin-top: 15px; color: #666;"><small>💡 提示: 点击文件名可直接下载包含MD文件和图片的ZIP文件</small></p>`;
                        document.getElementById('result').innerHTML = resultHtml;
                    }} else {{
                        document.getElementById('result').innerHTML = 
                            `<div class="error"><strong>❌ 处理失败:</strong> ${{result.detail}}</div>`;
                    }}
                    
                    document.getElementById('result').style.display = 'block';
                    
                }} catch (error) {{
                    clearInterval(progressInterval);
                    document.getElementById('loading').style.display = 'none';
                    document.getElementById('submitBtn').disabled = false;
                    document.getElementById('result').innerHTML = 
                        `<div class="error"><strong>❌ 网络错误:</strong> ${{error.message}}</div>`;
                    document.getElementById('result').style.display = 'block';
                }}
            }});
        </script>
    </body>
    </html>
    """
    return HTMLResponse(content=html_content)


@app.post("/zip_md_merge")
async def zip_md_merge(
    request: Request,
    file: UploadFile = File(...),
    transfer_html: bool = Form(True),
    max_files_per_group: int = Form(10)
):
    """
    处理ZIP文件中的Markdown文件合并，并返回包含MD文件和images目录的ZIP文件的下载链接
    
    Args:
        request: HTTP 请求对象，用于获取域名
        file: 上传的ZIP文件
        transfer_html: 是否转换HTML表格为Markdown格式
        max_files_per_group: 每组最大文件数
    
    Returns:
        JSON响应，包含处理后ZIP文件的完整http下载链接
    """
    
    # 验证文件类型
    if not file.filename.lower().endswith('.zip'):
        raise HTTPException(status_code=400, detail="只支持ZIP文件格式")
    
    # 验证文件大小
    if file.size and file.size > 50 * 1024 * 1024:  # 50MB限制
        raise HTTPException(status_code=400, detail="文件大小不能超过50MB")
    
    # 生成唯一的文件名
    unique_id = str(uuid.uuid4())
    temp_zip_path = os.path.join("uploads", f"{unique_id}_{file.filename}")
    
    try:
        # 保存上传的文件
        with open(temp_zip_path, "wb") as buffer:
            content = await file.read()
            buffer.write(content)
        
        # 验证 temp_zip_path 是字符串
        if not isinstance(temp_zip_path, str):
            raise HTTPException(status_code=500, detail="内部错误：ZIP文件路径不是字符串")
        
        # 处理文件并生成ZIP文件
        output_files, zip_output_path = service.process_zip_file(
            zip_file_path=temp_zip_path,
            transfer_html=transfer_html,
            max_files_per_group=max_files_per_group
        )
        
        # 动态获取基地址：优先使用环境变量，其次从请求头获取
        base_url = os.getenv("BASE_URL", DEFAULT_BASE_URL)
        if "host" in request.headers:
            scheme = request.headers.get("x-forwarded-proto", "http")
            host = request.headers.get("host")
            base_url = f"{scheme}://{host}"
        
        # 生成ZIP文件的完整http下载URL
        relative_path = os.path.relpath(zip_output_path, ".")
        download_url = f"{base_url}/{relative_path.replace(os.sep, '/')}"
        
        # 清理临时文件
        if os.path.exists(temp_zip_path):
            os.remove(temp_zip_path)
        
        return JSONResponse(content={
            "message": "文件处理成功",
            "zip_file": download_url
        })
        
    except Exception as e:
        # 清理临时文件
        if os.path.exists(temp_zip_path):
            os.remove(temp_zip_path)
        
        raise HTTPException(status_code=500, detail=f"处理文件时出错: {str(e)}")


@app.get("/health")
async def health_check():
    """健康检查接口"""
    return {"status": "healthy", "service": "zip-md-merge"}


def cleanup_old_files():
    """清理旧文件的后台任务"""
    import time
    import glob
    
    # 清理超过1小时的上传文件
    upload_files = glob.glob("uploads/*")
    current_time = time.time()
    
    for file_path in upload_files:
        if os.path.isfile(file_path):
            file_age = current_time - os.path.getctime(file_path)
            if file_age > 3600:  # 1小时
                try:
                    os.remove(file_path)
                except:
                    pass
    
    # 清理超过24小时的输出文件
    output_dirs = glob.glob("outputs/output_*")
    output_zips = glob.glob("outputs/*.zip")
    for dir_path in output_dirs:
        if os.path.isdir(dir_path):
            dir_age = current_time - os.path.getctime(dir_path)
            if dir_age > 86400:  # 24小时
                try:
                    shutil.rmtree(dir_path)
                except:
                    pass
    
    for zip_path in output_zips:
        if os.path.isfile(zip_path):
            zip_age = current_time - os.path.getctime(zip_path)
            if zip_age > 86400:  # 24小时
                try:
                    os.remove(zip_path)
                except:
                    pass


if __name__ == "__main__":
    import uvicorn
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)